home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************/
- /* */
- /* EVALUATE.C - A simple mathematical expression evaluator in C */
- /* */
- /* operators supported: Operator Precedence */
- /* */
- /* ( Lowest */
- /* ) Highest */
- /* + (addition) Low */
- /* - (subtraction) Low */
- /* * (multiplication) Medium */
- /* / (division) Medium */
- /* \ (modulus) High */
- /* ^ (exponentiation) High */
- /* sin( Lowest */
- /* cos( Lowest */
- /* atan( Lowest */
- /* abs( Lowest */
- /* sqrt( Lowest */
- /* ln( Lowest */
- /* exp( Lowest */
- /* */
- /* constants supported: pi */
- /* */
- /* Original Copyright 1991-93 by Robert B. Stout as part of */
- /* the MicroFirm Function Library (MFL) */
- /* */
- /* This subset version is hereby donated to the public domain. */
- /* Requires RMALLWS.C, also in SNIPPETS. */
- /* */
- /************************************************************************/
-
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <math.h>
-
- #define LAST_CHAR(string) (((char *)string)[strlen(string)-1])
-
- struct operator {
- char token;
- char *tag;
- size_t taglen;
- int precedence;
- };
-
- #define NUL '\0'
-
- typedef enum {R_ERROR = -2 /* range */, ERROR /* syntax */, SUCCESS} STATUS;
-
- static struct operator verbs[] = {
- {'+', "+", 1, 2 },
- {'-', "-", 1, 3 },
- {'*', "*", 1, 4 },
- {'/', "/", 1, 5 },
- {'\\', "\\", 1, 5 },
- {'^', "^", 1, 6 },
- {'(', "(", 1, 0 },
- {')', ")", 1, 99},
- {'S', "SIN(", 4, 0 },
- {'C', "COS(", 4, 0 },
- {'A', "ABS(", 4, 0 },
- {'L', "LN(", 3, 0 },
- {'E', "EXP(", 4, 0 },
- {'t', "ATAN(", 5, 0 },
- {'s', "SQRT(", 5, 0 },
- {NUL, NULL, 0, 0 }
- };
-
- static char op_stack[256]; /* Operator stack */
- static double arg_stack[256]; /* Argument stack */
- static char token[256]; /* Token buffer */
- static int op_sptr, /* op_stack pointer */
- arg_sptr, /* arg_stack pointer */
- parens, /* Nesting level */
- state; /* 0 = Awaiting expression
- 1 = Awaiting operator
- */
- const double Pi = 3.14159265358979323846;
-
- int evaluate(char *, double *);
-
- char *rmallws(char *); /* Also in SNIPPETS */
-
- static int do_op(void);
- static int do_paren(void);
- static void push_op(char);
- static void push_arg(double);
- static int pop_arg(double *);
- static int pop_op(int *);
- static char *get_exp(char *);
- static struct operator *get_op(char *);
- static int getprec(char);
- static int getTOSprec(void);
-
- #ifdef TEST
-
- #include <stdio.h>
-
- main(int argc, char *argv[])
- {
- int retval;
- double val;
-
- printf("evaluate(%s) ", argv[1]);
- printf("returned %d\n", retval = evaluate(argv[1], &val));
- if (0 == retval)
- printf("val = %f\n", val);
- return 0;
- }
-
- #endif
-
- /************************************************************************/
- /* */
- /* evaluate() */
- /* */
- /* Evaluates an ASCII mathematical expression. */
- /* */
- /* Arguments: 1 - String to evaluate */
- /* 2 - Storage to receive double result */
- /* */
- /* Returns: SUCCESS if successful */
- /* ERROR if syntax error */
- /* R_ERROR if runtime error */
- /* */
- /* Side effects: Removes all whitespace from the string and converts */
- /* it to U.C. */
- /* */
- /************************************************************************/
-
- int evaluate(char *line, double *val)
- {
- double arg;
- char *ptr = line, *str, *endptr;
- int ercode;
- struct operator *op;
-
- strupr(line);
- rmallws(line);
- state = op_sptr = arg_sptr = parens = 0;
-
- while (*ptr)
- {
- switch (state)
- {
- case 0:
- if (NULL != (str = get_exp(ptr)))
- {
- if (NULL != (op = get_op(str)) &&
- strlen(str) == op->taglen)
- {
- push_op(op->token);
- ptr += op->taglen;
- break;
- }
-
- if (SUCCESS == strcmp(str, "-"))
- {
- push_op(*str);
- ++ptr;
- break;
- }
-
- if (SUCCESS == strcmp(str, "PI"))
- push_arg(Pi);
-
- else
- {
- if (0.0 == (arg = strtod(str, &endptr)) &&
- NULL == strchr(str, '0'))
- {
- return ERROR;
- }
- push_arg(arg);
- }
- ptr += strlen(str);
- }
- else return ERROR;
-
- state = 1;
- break;
-
- case 1:
- if (NULL != (op = get_op(ptr)))
- {
- if (')' == *ptr)
- {
- if (SUCCESS > (ercode = do_paren()))
- return ercode;
- }
- else
- {
- while (op_sptr &&
- op->precedence <= getTOSprec())
- {
- do_op();
- }
- push_op(op->token);
- state = 0;
- }
-
- ptr += op->taglen;
- }
- else return ERROR;
-
- break;
- }
- }
-
- while (1 < arg_sptr)
- {
- if (SUCCESS > (ercode = do_op()))
- return ercode;
- }
- if (!op_sptr)
- return pop_arg(val);
- else return ERROR;
- }
-
- /*
- ** Evaluate stacked arguments and operands
- */
-
- static int do_op(void)
- {
- double arg1, arg2;
- int op;
-
- if (ERROR == pop_op(&op))
- return ERROR;
-
- pop_arg(&arg1);
- pop_arg(&arg2);
-
- switch (op)
- {
- case '+':
- push_arg(arg2 + arg1);
- break;
-
- case '-':
- push_arg(arg2 - arg1);
- break;
-
- case '*':
- push_arg(arg2 * arg1);
- break;
-
- case '/':
- if (0.0 == arg1)
- return R_ERROR;
- push_arg(arg2 / arg1);
- break;
-
- case '\\':
- if (0.0 == arg1)
- return R_ERROR;
- push_arg(fmod(arg2, arg1));
- break;
-
- case '^':
- push_arg(pow(arg2, arg1));
- break;
-
- case 't':
- ++arg_sptr;
- push_arg(atan(arg1));
- break;
-
- case 'S':
- ++arg_sptr;
- push_arg(sin(arg1));
- break;
-
- case 's':
- if (0.0 > arg2)
- return R_ERROR;
- ++arg_sptr;
- push_arg(sqrt(arg1));
- break;
-
- case 'C':
- ++arg_sptr;
- push_arg(cos(arg1));
- break;
-
- case 'A':
- ++arg_sptr;
- push_arg(fabs(arg1));
- break;
-
- case 'L':
- if (0.0 < arg1)
- {
- ++arg_sptr;
- push_arg(log(arg1));
- break;
- }
- else return R_ERROR;
-
- case 'E':
- ++arg_sptr;
- push_arg(exp(arg1));
- break;
-
- case '(':
- arg_sptr += 2;
- break;
-
- default:
- return ERROR;
- }
- if (1 > arg_sptr)
- return ERROR;
- else return op;
- }
-
- /*
- ** Evaluate one level
- */
-
- static int do_paren(void)
- {
- int op;
-
- if (1 > parens--)
- return ERROR;
- do
- {
- if (SUCCESS > (op = do_op()))
- break;
- } while (getprec((char)op));
- return op;
- }
-
- /*
- ** Stack operations
- */
-
- static void push_op(char op)
- {
- if (!getprec(op))
- ++parens;
- op_stack[op_sptr++] = op;
- }
-
- static void push_arg(double arg)
- {
- arg_stack[arg_sptr++] = arg;
- }
-
- static int pop_arg(double *arg)
- {
- *arg = arg_stack[--arg_sptr];
- if (0 > arg_sptr)
- return ERROR;
- else return SUCCESS;
- }
-
- static int pop_op(int *op)
- {
- if (!op_sptr)
- return ERROR;
- *op = op_stack[--op_sptr];
- return SUCCESS;
- }
-
- /*
- ** Get an expression
- */
-
- static char * get_exp(char *str)
- {
- char *ptr = str, *tptr = token;
- struct operator *op;
-
- if (SUCCESS == strncmp(str, "PI", 2))
- return strcpy(token, "PI");
-
-
- while (*ptr)
- {
- if (NULL != (op = get_op(ptr)))
- {
- if ('-' == *ptr)
- {
- if (str != ptr && 'E' != ptr[-1])
- break;
- if (str == ptr && !isdigit(ptr[1]) && '.' != ptr[1])
- {
- push_arg(0.0);
- strcpy(token, op->tag);
- return token;
- }
- }
-
- else if (str == ptr)
- {
- strcpy(token, op->tag);
- return token;
- }
-
- else break;
- }
-
- *tptr++ = *ptr++;
- }
- *tptr = NUL;
-
- return token;
- }
-
- /*
- ** Get an operator
- */
-
- static struct operator * get_op(char *str)
- {
- struct operator *op;
-
- for (op = verbs; op->token; ++op)
- {
- if (SUCCESS == strncmp(str, op->tag, op->taglen))
- return op;
- }
- return NULL;
- }
-
- /*
- ** Get precedence of a token
- */
-
- static int getprec(char token)
- {
- struct operator *op;
-
- for (op = verbs; op->token; ++op)
- {
- if (token == op->token)
- break;
- }
- if (op->token)
- return op->precedence;
- else return 0;
- }
-
- /*
- ** Get precedence of TOS token
- */
-
- static int getTOSprec(void)
- {
- if (!op_sptr)
- return 0;
- return getprec(op_stack[op_sptr - 1]);
- }
-